home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 10 - 1994 / 10.09 Sep 94 / Fez (MacHack Winner) / FezEdit ƒ / GetLineThick.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-20  |  17.6 KB  |  721 lines  |  [TEXT/MMCC]

  1. /*
  2.  *    Dialog Module, created by Resorcerer
  3.  */
  4.  
  5. #include "Main.h"
  6. #include "Fez.h"
  7. #include "Utilities.h"
  8. #include <stdarg.h>
  9.  
  10. #define thisDialogID 128
  11.  
  12. /* Symbolic Dialog Item Numbers */
  13.  
  14. static enum {
  15.     BUT1_OK = 1,
  16.     BUT2_Cancel,
  17.     EDIT3,
  18.     STXT4_Thickness,
  19.     STXT5_Speed,
  20.     STXT6_Queue,
  21.     LASTITEM
  22.     };
  23.  
  24. #define OK_ITEM     BUT1_OK
  25. #define CANCEL_ITEM     BUT2_Cancel
  26.  
  27. /* Useful constants */
  28.  
  29. #ifndef ENTERkey
  30. #define ENTERkey    0x3
  31. #endif
  32. #ifndef DELETEkey
  33. #define DELETEkey    0x8
  34. #endif
  35. #ifndef NIL
  36. #define NIL ((void *)0)
  37. #endif
  38. #ifndef TRUE
  39. #define TRUE 1
  40. #endif
  41. #ifndef FALSE
  42. #define FALSE 0
  43. #endif
  44. #ifndef FRONT_WINDOW
  45. #define FRONT_WINDOW  ((WindowPtr) (-1L))
  46. #endif
  47.  
  48. /* Prototypes */
  49.  
  50. short      GetLineThickOrSpeed(short oldVal, int doSpeed);
  51. DialogPtr OpenThisDialog(void);
  52. void      CloseThisDialog(DialogPtr dlog);
  53. void      DoDialogUpdate(DialogPtr dlog);
  54. void      DoDialogActivate(DialogPtr dlog, int activ);
  55. void      DoDialogContent(DialogPtr dlog, EventRecord *evt);
  56. int       DoDialogItem(DialogPtr dlog, short itemHit);
  57.  
  58. pascal  Boolean MyFilter(DialogPtr dlog, EventRecord *evt, short *itemHit);
  59. Boolean CheckUserItems(Point where, short *itemHit);
  60. int     AnyBadValues(DialogPtr dlog);
  61.  
  62. void    CenterWindow(WindowPtr w, int top);
  63. long    strlen(char *);
  64. char   *strcpy(char *dst, char *src);
  65. char   *PascalToC(unsigned char *pstr);
  66. unsigned char   *CToPascal(char *cstr);
  67. void    PutDlgString(DialogPtr dlog, int item, unsigned char *str, int sel);
  68. void    PutDlgWord(DialogPtr dlog, int item, int val, int sel);
  69. void    PutDlgLong(DialogPtr dlog, int item, long val, int sel);
  70. void    PutDlgChkRadio(DialogPtr dlog, int item, int val);
  71. int     GetDlgString(DialogPtr dlog, int item, unsigned char *str);
  72. int     GetDlgWord(DialogPtr dlog, int item, short *val);
  73. int     GetDlgLong(DialogPtr dlog, int item, long *val);
  74. int     GetDlgChkRadio(DialogPtr dlog, int item);
  75. int     TextSelected(DialogPtr dlog);
  76. OSType  CanPaste(int n, ...);
  77. void    FrameDefault(DialogPtr dlog, int item, int frame);
  78. void    GetDlgPanel(DialogPtr dlog, int item, Rect *panel);
  79.  
  80. static Point where;
  81. static int modifiers;
  82. static int doingSpeed;
  83. static short theThick;
  84.  
  85. /*
  86.  *    Display this modal dialog.  Return TRUE if OK, FALSE if CANCEL or error.
  87.  *    If the dialog displays values from outside this module, you should either
  88.  *    import them from globals, or change the argument list of this routine to
  89.  *    bring them in and pass them to OpenThisDialog(), DoDialogItem(), etc.
  90.  */
  91.  
  92. short GetLineThickOrSpeed(short oldVal, int doSpeed)
  93.     {
  94.         short itemHit,okay,keepGoing=TRUE;
  95.         register DialogPtr dlog; GrafPtr oldPort;
  96.         static ModalFilterUPP MyFilterUPP;
  97.         
  98.         if (MyFilterUPP == NIL) {
  99.             MyFilterUPP = NewModalFilterProc(MyFilter);
  100.             if (MyFilterUPP == NIL) return(FALSE);
  101.             }
  102.         
  103.         theThick = oldVal;
  104.         doingSpeed = doSpeed;
  105.         
  106.         /* Build dialog window and install its item values */
  107.         
  108.         GetPort(&oldPort);
  109.         dlog = OpenThisDialog();
  110.         if (dlog == NIL) return(FALSE);
  111.  
  112.         /* Entertain filtered user events until dialog is dismissed */
  113.         
  114.         while (keepGoing) {
  115.             ModalDialog(MyFilterUPP,&itemHit);
  116.             keepGoing = DoDialogItem(dlog,itemHit);
  117.             }
  118.         
  119.         /*
  120.          *    Do final processing of item values, such as exporting them to caller.
  121.          *    DoDialogItem() has already called AnyBadValues().
  122.          */
  123.         
  124.         okay = (itemHit==OK_ITEM);
  125.         if (okay) {                        /* Or whatever is equivalent */
  126.             oldVal = theThick;
  127.             }
  128.          else
  129.             oldVal = (doingSpeed==2) ? 0 : (doingSpeed==1) ? -1 : 0;
  130.  
  131.         /* That's all, folks! */
  132.         
  133.         CloseThisDialog(dlog);
  134.         SetPort(oldPort);
  135.         
  136.         return(oldVal);
  137.     }
  138.  
  139. /*
  140.  *    We have to have a filter function, at the very least so that we can outline
  141.  *    any default button, entertain keyboard editing commands, cmd-period canceling, etc.
  142.  *    Note that you do not need to have a special user item covering the default button
  143.  *    in your dialog item list.
  144.  */
  145.  
  146. static pascal Boolean MyFilter(DialogPtr dlog, EventRecord *evt, short *itemHit)
  147.     {
  148.         Boolean ans=FALSE,doHilite=FALSE; WindowPtr w;
  149.         short type,ch; Handle hndl; Rect box;
  150.         static long then; static Point clickPt;
  151.         
  152.         w = (WindowPtr)(evt->message);
  153.         switch(evt->what) {
  154.             case updateEvt:
  155.                 if (w == dlog) {
  156.                     /* Update our dialog contents */
  157.                     DoDialogUpdate(dlog);
  158.                     ans = TRUE; *itemHit = 0;
  159.                     }
  160.                  else {
  161.                     /*
  162.                      *    Call your main event loop DoUpdate(w) routine here if you
  163.                      *    don't want unsightly holes in background windows caused
  164.                      *    by nested alerts, balloon help, or screen savers (see
  165.                      *    Tech Note #304).
  166.                      */
  167.                     }
  168.                 break;
  169.             case activateEvt:
  170.                 if (w == dlog) {
  171.                     DoDialogActivate(dlog,(evt->modifiers & activeFlag)!=0);
  172.                     *itemHit = 0;
  173.                     }
  174.                  else {
  175.                     /*
  176.                      *    Call your main event loop DoActivate(w) routine here if
  177.                      *    you want to deactivate the former frontmost window, in order
  178.                      *    to unhighlight any selection, scroll bars, etc.
  179.                      */
  180.                     }
  181.                 break;
  182.             case mouseDown:
  183.             case mouseUp:
  184.                 where = evt->where;        /* Make info available to DoDialog() */
  185.                 GlobalToLocal(&where);
  186.                 modifiers = evt->modifiers;
  187.                 ans = CheckUserItems(where,itemHit);
  188.                 break;
  189.             case keyDown:
  190.                 if ((ch=(unsigned char)evt->message)=='\r' || ch==ENTERkey) {
  191.                     *itemHit = OK_ITEM /* Default Item Number here */;
  192.                     doHilite = ans = TRUE;
  193.                     }
  194.                  else if (evt->modifiers & cmdKey) {
  195.                     ch = (unsigned char)evt->message;
  196.                     switch(ch) {
  197.                         case 'x':
  198.                         case 'X':
  199.                             if (TextSelected(dlog))
  200.                                 { SystemEdit(3); ZeroScrap(); DlgCut(dlog); TEToScrap(); }
  201.                              else {
  202.                                 /* Cut from anything else cuttable, like a list */
  203.                                 }
  204.                             break;
  205.                         case 'c':
  206.                         case 'C':
  207.                             if (TextSelected(dlog))
  208.                                 { SystemEdit(3); ZeroScrap(); DlgCopy(dlog); TEToScrap(); }
  209.                              else {
  210.                                 /* Copy from anything else copyable, like a list */
  211.                                 }
  212.                             break;
  213.                         case 'v':
  214.                         case 'V':
  215.                             if (CanPaste(1,'TEXT'))
  216.                                 { TEFromScrap(); DlgPaste(dlog); }
  217.                              else {
  218.                                  /* Deal with any other pasteable scraps here */
  219.                                 }
  220.                             break;
  221.                         case 'a':
  222.                         case 'A':
  223.                             if (((DialogPeek)dlog)->editField >= 0) {
  224.                                 /* Dialog has text edit item: select all */
  225.                                 SelIText(dlog,((DialogPeek)dlog)->editField+1,0,32767);
  226.                                 }
  227.                              else {
  228.                                 }
  229.                             *itemHit = 0;
  230.                             break;
  231.                         case '.':
  232.                             *itemHit = CANCEL_ITEM;
  233.                             doHilite = TRUE;
  234.                             break;
  235.                         }
  236.                     ans = TRUE;        /* Other cmd-chars ignored */
  237.                     }
  238.                 break;
  239.             }
  240.         if (doHilite) {
  241.             GetDItem(dlog,*itemHit,&type,&hndl,&box);
  242.             /* Reality check */
  243.             if (type == (btnCtrl+ctrlItem)) {
  244.                 long soon = TickCount() + 7;        /* Or whatever feels right */
  245.                 HiliteControl((ControlHandle)hndl,1);
  246.                 while (TickCount() < soon) ;        /* Leave hilited for a bit */
  247.                 }
  248.             }
  249.         return(ans);
  250.     }
  251.  
  252. /*
  253.  * Mouse down event:
  254.  * Check if it's in some user item, and convert to itemHit if appropriate.
  255.  */
  256.  
  257. static Boolean CheckUserItems(Point where, short *itemHit)
  258.     {
  259.         return(FALSE);
  260.     }
  261.  
  262. /*
  263.  * Redraw the contents of this dialog due to update event.
  264.  * If you have not installed UserItem draw routines, you should redraw
  265.  * them explicitly here; otherwise, UpdtDialog() will call your routines.
  266.  */
  267.  
  268. static void DoDialogUpdate(DialogPtr dlog)
  269.     {
  270.         GrafPtr oldPort;
  271.  
  272.         GetPort(&oldPort); SetPort(dlog);
  273.         BeginUpdate(dlog);
  274.  
  275.         UpdtDialog(dlog,dlog->visRgn);
  276.         FrameDefault(dlog,BUT1_OK,TRUE);
  277.  
  278.         EndUpdate(dlog);
  279.         SetPort(oldPort);
  280.     }
  281.  
  282. /*
  283.  * Activate event: Activate or deactivate this dialog and any items in it
  284.  */
  285.  
  286. static void DoDialogActivate(DialogPtr dlog, int activ)
  287.     {
  288.         SetPort(dlog);
  289.     }
  290.  
  291. /*
  292.  * Build this dialog's window on desktop, and install initial item values.
  293.  * Return the dlog opened, or NIL if error (no resource, no memory).
  294.  */
  295.  
  296. static DialogPtr OpenThisDialog()
  297.     {
  298.         GrafPtr oldPort; DialogPtr dlog;
  299.         Rect bounds;
  300.         
  301.         GetPort(&oldPort);
  302.         dlog = GetNewDialog(thisDialogID,NIL,FRONT_WINDOW);
  303.         if (dlog == NIL) { SysBeep(1); return(NIL); }    /* Poor man's error message */
  304.  
  305.         CenterWindow(dlog,0);
  306.         bounds = dlog->portRect;
  307.         LocalToGlobalRect(dlog,&bounds);
  308.         MoveWindow(dlog,bounds.left,100,FALSE);
  309.         
  310.         SetPort(dlog);
  311.  
  312.         /* Fill in dialog's values here */
  313.  
  314.         PutDlgWord(dlog, EDIT3, theThick, TRUE);
  315.         if (doingSpeed == 2) {
  316.             ShowDItem(dlog,STXT6_Queue);
  317.             HideDItem(dlog,STXT5_Speed);
  318.             HideDItem(dlog,STXT4_Thickness);
  319.             }
  320.          else if (doingSpeed == 1) {
  321.             HideDItem(dlog,STXT6_Queue);
  322.             ShowDItem(dlog,STXT5_Speed);
  323.             HideDItem(dlog,STXT4_Thickness);
  324.             }
  325.          else {
  326.             HideDItem(dlog,STXT6_Queue);
  327.             HideDItem(dlog,STXT5_Speed);
  328.             ShowDItem(dlog,STXT4_Thickness);
  329.             }
  330.         ShowWindow(dlog);
  331.         return(dlog);
  332.  
  333.     }
  334.  
  335. /*
  336.  * Clean up any allocated stuff, and return dialog to primordial mists
  337.  */
  338.  
  339. static void CloseThisDialog(DialogPtr dlog)
  340.     {
  341.         DisposDialog(dlog);    /* Call CloseDialog if you provide storage to GetNewDialog */
  342.     }
  343.  
  344. /*
  345.  * Deal with user clicking on an item in this dialog, either modal or non-modal.
  346.  * The local point is in where; modifiers in modifiers.
  347.  * Returns whether or not the dialog should be closed (keepGoing).
  348.  */
  349.  
  350. static int DoDialogItem(DialogPtr dlog, short itemHit)
  351.     {
  352.         short type,okay=FALSE,keepGoing=TRUE;
  353.         Handle hndl; Rect box;
  354.  
  355.         if (itemHit<1 || itemHit>=LASTITEM)
  356.             return(keepGoing);                /* Only legal items, please */
  357.  
  358.         GetDItem(dlog,itemHit,&type,&hndl,&box);
  359.         switch(type) {
  360.             case ctrlItem+btnCtrl:
  361.                 switch(itemHit) {
  362.                     case BUT1_OK:
  363.                         keepGoing = FALSE; okay = TRUE;
  364.                         break;
  365.                     case BUT2_Cancel:
  366.                         keepGoing = FALSE;
  367.                         break;
  368.                     }
  369.                 break;
  370.             case ctrlItem+chkCtrl:
  371.                 break;
  372.             case ctrlItem+radCtrl:
  373.                 break;
  374.             case ctrlItem+resCtrl:
  375.                 break;
  376.             case statText:
  377.                 switch(itemHit) {
  378.                     case STXT4_Thickness:        /* NOT Enabled */
  379.                         break;
  380.                     case STXT5_Speed:            /* NOT Enabled */
  381.                         break;
  382.                     }
  383.                 break;
  384.             case editText:
  385.                 switch(itemHit) {
  386.                     case EDIT3:
  387.                         break;
  388.                     }
  389.                 break;
  390.             case iconItem:
  391.                 break;
  392.             case picItem:
  393.                 break;
  394.             case userItem:
  395.                 break;
  396.             }
  397.  
  398.         if (okay) keepGoing = AnyBadValues(dlog);
  399.         return(keepGoing);
  400.     }
  401.  
  402. /*
  403.  * Pull values out of dialog items and deliver TRUE if any of them are
  404.  * illegal or inconsistent; otherwise deliver FALSE.  If any values are bad,
  405.  * you should inform your user about the problem here before delivering TRUE.
  406.  * If any items are missing values, this is the place to assign any defaults.
  407.  */
  408.  
  409. static int AnyBadValues(DialogPtr dlog)
  410.     {
  411.         if (GetDlgWord(dlog,EDIT3,&theThick)) {
  412.             /* Got a string (can also call GetDlgWord(), etc. here) */
  413.             if (doingSpeed == 2) {
  414.                 if (theThick<1 || theThick>MAXQUEUE) {
  415.                     SysBeep(1);
  416.                     return(TRUE);
  417.                     }
  418.                 }
  419.              else if (doingSpeed == 1) {
  420.                 if (theThick<0 || theThick>60) {
  421.                     SysBeep(1);
  422.                     return(TRUE);
  423.                     }
  424.                 }
  425.              else {
  426.                 if (theThick<1 || theThick>16) {
  427.                     SysBeep(1);
  428.                     return(TRUE);
  429.                     }
  430.                 }
  431.             }
  432.         else {
  433.             /* Field was empty */
  434.             }
  435.         return(FALSE);
  436.     }
  437.  
  438. /*••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
  439.  
  440. /*
  441.  *  The following are various utility routines for general dialog management.
  442.  *  Typically, you'll want to keep them in a library that is available to all
  443.  *  your dialog modules; however, they are included here (and declared static)
  444.  *  as a private library so that you can quickly compile this file for testing.
  445.  */
  446.  
  447. #define _PrivateLibraries_
  448. #ifdef  _PrivateLibraries_
  449.  
  450. /*
  451.  *    Center a given window, w, horizontally in the main screen, top pixels from
  452.  *    the top, or centered vertically if top is 0.  The window should be invisible.
  453.  */
  454.  
  455. static void CenterWindow(WindowPtr w, int top)
  456.     {
  457.         Rect scr; Point p;
  458.         int rsize,size,margin;
  459.  
  460.         scr = qd.screenBits.bounds;
  461.         SetPort(w);
  462.         p.h = w->portRect.left; p.v = w->portRect.top;
  463.         LocalToGlobal(&p);
  464.  
  465.         size = scr.right - scr.left;
  466.         rsize = w->portRect.right - w->portRect.left;
  467.         margin = size - rsize;
  468.         if (margin > 0) {
  469.             margin >>= 1;
  470.             p.h = scr.left + margin;
  471.             }
  472.         size = scr.bottom - scr.top;
  473.         rsize = w->portRect.bottom - w->portRect.top;
  474.         margin = size - rsize;
  475.         if (margin > 0) {
  476.             margin >>= 1;
  477.             p.v = scr.top + margin;
  478.             }
  479.         MoveWindow(w,p.h,top?top:p.v,FALSE);
  480.     }
  481.  
  482. /* Local C string length routine */
  483.  
  484. static long strlen(register char *str)
  485.     {
  486.         register char *p;
  487.  
  488.         p = str;
  489.         while (*p++) ;
  490.         return((long)(--p - str));
  491.     }
  492.  
  493. /* Convert in place a Pascal string to C string, and deliver its address */
  494.  
  495. static char *PascalToC(unsigned char *str)
  496.     {
  497.         register unsigned char *p,*q,*end;
  498.  
  499.         end = str + *(unsigned char *)str;
  500.         q = (p=str) + 1;
  501.         while (p < end) *p++ = *q++;
  502.         *p = '\0';
  503.         return((char *)str);
  504.     }
  505.  
  506. /*
  507.  *    Convert in place a C string to Pascal string, and deliver its address.
  508.  *    The C string should not be greater than 255 chars in length, or the
  509.  *    resulting Pascal string will be truncated to 255 chars.
  510.  */
  511.  
  512. static unsigned char *CToPascal(char *str)
  513.     {
  514.         register char *p,*q;
  515.         register long len;
  516.  
  517.         len = strlen(str);
  518.         if (len > 255) len = 255;
  519.         p = str + len;
  520.         q = p-1;
  521.         while (p != str) *p-- = *q--;
  522.         *str = len;
  523.         return((unsigned char *)str);
  524.     }
  525.  
  526. /* Dialog Item Stuffers */
  527.  
  528. /*
  529.  *    Install a given Pascal string, str, into the given static or edit text item
  530.  *    in the dialog, dlog.  If the item is an edit text item, leave the installed
  531.  *    text selected or not according to the value of sel (TRUE or FALSE).
  532.  */
  533.  
  534. static void PutDlgString(DialogPtr dlog, int item, unsigned char *str, int sel)
  535.     {
  536.         short type; Handle hndl; Rect box;
  537.  
  538.         GetDItem(dlog,item,&type,&hndl,&box);
  539.         SetIText(hndl,str);
  540.         if (type == editText)
  541.             SelIText(dlog,item,sel?0:32767,32767);
  542.         InvalRect(&box);
  543.     }
  544.  
  545. /*
  546.  *    Install a given decimal long value into the static or edit text item of the
  547.  *    given dialog, dlog.  If the item is an edit text item, leave the installed
  548.  *    text for the number selected or not according to sel (TRUE or FALSE).
  549.  */
  550.  
  551. static void PutDlgLong(DialogPtr dlog, int item, long val, int sel)
  552.     {
  553.         unsigned char str[32];
  554.  
  555.         NumToString(val,str);
  556.         PutDlgString(dlog,item,str,sel);
  557.     }
  558.  
  559. /*
  560.  *    Same as above, only for an int (word) decimal number.
  561.  */
  562.  
  563. static void PutDlgWord(DialogPtr dlog, int item, int val, int sel)
  564.     {
  565.         PutDlgLong(dlog,item,(long)val,sel);
  566.     }
  567.  
  568. /*
  569.  *    Set the given check box or radio button item of the given dialog, dlog, to
  570.  *    on or off, according to val.
  571.  */
  572.  
  573. static void PutDlgChkRadio(DialogPtr dlog, int item, int val)
  574.     {
  575.         short type; Handle hndl; Rect box;
  576.  
  577.         GetDItem(dlog,item,&type,&hndl,&box);
  578.         SetCtlValue((ControlHandle)hndl,val!=0);
  579.     }
  580.  
  581. /*
  582.  *    Deliver the value of the checkbox or radio button item of the given dialog.
  583.  */
  584.  
  585. static int GetDlgChkRadio(DialogPtr dlog, int item)
  586.     {
  587.         short type; Handle hndl; Rect box;
  588.         
  589.         GetDItem(dlog,item,&type,&hndl,&box);
  590.         return(GetCtlValue((ControlHandle)hndl) != 0);
  591.     }
  592.  
  593. /* Dialog Item Unstuffers */
  594.  
  595. /*
  596.  *    Retrieve the value of an edit text item in a given dialog, placing the
  597.  *    resulting Pascal string in the buffer, str, which is assumed large enough
  598.  *    to hold the text (256 bytes max).  If item is the number of a static text
  599.  *    item, the empty string is delivered.  Delivers TRUE or FALSE according to
  600.  *    whether or not the text so delivered was empty.  
  601.  */
  602.  
  603. static int GetDlgString(DialogPtr dlog, int item, unsigned char *str)
  604.     {
  605.         short type; Handle hndl; Rect box;
  606.  
  607.         GetDItem(dlog,item,&type,&hndl,&box);
  608.         if (type == editText) GetIText(hndl,str);
  609.          else                 *str = 0;
  610.         return(*str != 0);
  611.     }
  612.  
  613. /*
  614.  *    Retrieve the value of an edit text item in a given dialog, converting the
  615.  *    Pascal string to a long and setting *val to it.  Delivers TRUE or FALSE
  616.  *    according to whether or not the text so delivered was empty.  If FALSE,
  617.  *    *val is set to 0; if TRUE, *val is set to whatever StringToNum() says the
  618.  *    value is, even if the text contains non-numerical characters.
  619.  */
  620.  
  621. static int GetDlgLong(DialogPtr dlog, int item, long *val)
  622.     {
  623.         int ans; unsigned char str[256];
  624.  
  625.         *val = 0;
  626.         ans = GetDlgString(dlog,item,str);
  627.         if (ans)
  628.             StringToNum(str,val);
  629.         return(ans);
  630.         }
  631.  
  632. /* Same as above, only delivers the value of a word */
  633.  
  634. static int GetDlgWord(DialogPtr dlog, int item, short *val)
  635.     {
  636.         int ans; long num;
  637.  
  638.         *val = 0;
  639.         ans = GetDlgLong(dlog,item,&num);
  640.         if (ans)
  641.             *val = num;
  642.         return(ans);
  643.     }
  644.  
  645. /*
  646.  *    Deliver the number of the current editText item in given dialog if any text
  647.  *    is selected in it, or 0 if none selected.
  648.  */
  649.  
  650. int TextSelected(DialogPtr dlog)
  651.     {
  652.         register TEHandle textH; int item = 0;
  653.         
  654.         textH = ((DialogPeek)dlog)->textH;
  655.         if (*textH)
  656.             if ( (*textH)->selStart != (*textH)->selEnd )
  657.                 item = ((DialogPeek)dlog)->editField+1;
  658.         return(item);
  659.     }
  660.  
  661. /*
  662.  *  If any of the variable argument scrap types are available for pasting from
  663.  *  the scrap, deliver the first one.  Otherwise, deliver 0.  For example,
  664.  *    
  665.  *      if (whichType = CanPaste(3,'TEXT','PICT','STUF')) ...
  666.  *
  667.  *  There can be any number of types in the list, as long as the preceding count, n,
  668.  *  is correct.
  669.  */
  670.  
  671. static OSType CanPaste(int n, ...)
  672.     {
  673.         register OSType nextType,ans = 0L;
  674.         long err,offset;
  675.         va_list nextArg;
  676.         
  677.         va_start(nextArg,n);
  678.         nextType = va_arg(nextArg, OSType);
  679.         
  680.         while (n-- > 0) {
  681.             err = GetScrap(NIL, nextType, &offset);
  682.             if (err >= -1) {
  683.                 ans = nextType;
  684.                 break;
  685.                 }
  686.             nextType = va_arg(nextArg, OSType);
  687.             }
  688.         
  689.         va_end(nextArg);
  690.         return(ans);
  691.     }
  692.  
  693. /*
  694.  *    Frame or unframe a default dialog item (presumed a button) in given dialog.
  695.  *    Note that you don't need to use an extra user item to do this unless you
  696.  *    are doing some sort of non-standard default highlighting (not recommended).
  697.  */
  698.  
  699. static void FrameDefault(DialogPtr dlog, int item, int frame)
  700.     {
  701.         short type; Handle hndl; Rect box;
  702.         GrafPtr oldPort; PenState oldPen;
  703.         
  704.         GetPort(&oldPort); SetPort(dlog);
  705.         GetPenState(&oldPen);
  706.         
  707.         GetDItem(dlog,item,&type,&hndl,&box);
  708.         InsetRect(&box,-4,-4);
  709.         
  710.         PenSize(3,3);
  711.         if (frame) PenPat(&qd.black);        /* Paint frame */
  712.          else      PenPat(&qd.white);        /* Erase frame */
  713.         FrameRoundRect(&box,16,16);
  714.         
  715.         SetPenState(&oldPen);
  716.         SetPort(oldPort);
  717.     }
  718.  
  719. #endif
  720.  
  721.